// // DEBUG:
// #include <qfile.h>
// #include <qtextstream.h>

#include <qdatastream.h>

#include "BnetDefinitions.h"

#include "BnetPacketParser.h"

// Note: We don't handle multiple packets in a single QByteArray.
// Also, I'm assuming that we will only see Bnet messages in this
// QByteArray.


// Turns QByteArray into BnetMessage.
BnetMessage BnetPacketParser::parsePacket( const QByteArray& arr )
{
//     QFile debugfile( "debugpacketparser.txt" );
//     debugfile.open( IO_WriteOnly | IO_Append );
//     QTextStream debug( &debugfile );
    
    if( arr.size() == 0 )
    {
// 	debug << "DEBUG:  Throwing away blank QByteArray." << "\n";
	return BnetMessage( BnetMessage::Null );
    }

    QDataStream stream( arr, IO_ReadOnly );
    stream.setByteOrder( QDataStream::LittleEndian );
    Q_UINT8 initialByte;
    stream >> initialByte;

    if( (arr.size() < 4) || initialByte != 0xFF )
    {
// 	debug << "DEBUG:  Corrupt package received.  Trashing." << "\n";
	return BnetMessage( BnetMessage::Null );
    }

    Q_UINT8 pktID;
    Q_UINT16 pktSize;

    stream >> pktID;
    stream >> pktSize;
    
//     debug << QString("pktID == ") << pktID << "\n";
//     debug << QString("QByteArray.size() == ") + 
// 	QString::number( arr.size() ) + 
// 	QString("; pktSize == ") + 
// 	QString::number( pktSize ) + "\n";
    
    if( arr.size() != pktSize )
    {
// 	debug <<  QString("WARNING:  Packet size mismatch detected!\n");
	return BnetMessage( BnetMessage::Null );
    }
    
    BnetMessage rv;
    rv.pktID = pktID;
    switch ( rv.pktID )
    {
    case SID_FLOODDETECTED:
    {
	rv.type = BnetMessage::NonChatEvent;
	rv.text = "Flood detected.";
// 	debugfile.close();
	return rv;
	break;
    }
    case SID_ENTERCHAT:
    {
	rv.type = BnetMessage::EnterChat;
	rv.user = this->fromUtf8toQString( stream );
//     debugfile.close();
	return rv;
	break;
    }
    case SID_LEAVECHAT:
    {
	rv.type = BnetMessage::LeaveChat;
// 	debugfile.close();
	return rv;
	break;
    }
    case SID_CHATEVENT:
    {
	rv.type = BnetMessage::ChatEvent;
	Q_UINT32 dummy;

	stream >> rv.eventID;
	stream >> rv.flags;
	stream >> rv.ping;

	// Defunct values.
	stream >> dummy;
	stream >> dummy;
	stream >> dummy;


	rv.user = this->fromUtf8toQString( stream );
	rv.text = this->fromUtf8toQString( stream );

// 	debug << "DEBUG:  ChatEvent." << "\n"
// 	      << "        eventID == " << rv.eventID << "\n"
// 	      << "        flags   == " << rv.flags << "\n"
// 	      << "        ping    == " << rv.ping << "\n"
// 	      << "        user    == " << rv.user << "\n"
// 	      << "        text    == " << rv.text << "\n";

	if( !stream.atEnd() )
	{
// 	    debug << "WARNING:  There is more to read from the byte stream!" 
// 		  << "\n";
	}

	
	bool debug_testingFriendJoin = checkIfFriendJoinedGame( rv );
	
	if( debug_testingFriendJoin )
	{
// 	    debug << "DEBUG:  friend joined game.  game name was: *"
// 		  << rv.gameName << "*\n";
	}
// 	debugfile.close();
	return rv;
	break;
    }
    case SID_CHATCOMMAND:
    {
	rv.type = BnetMessage::ChatCommand;
	rv.text = this->fromUtf8toQString( stream );
// 	debugfile.close();
	return rv;
	break;
    }
    default:
    {
	rv.type = BnetMessage::Null;
// 	debugfile.close();
	return rv;
	break;
    }
    }

//     debugfile.close();
}

// Changes the message type to FriendJoinedGame if that's true, and
// sets the game name.
bool BnetPacketParser::checkIfFriendJoinedGame( BnetMessage &msg )
{
    if( msg.eventID != EID_WHISPER )
    {
	return false;
    }
    
    QString text = msg.text;
    QString str1 = "Your friend ";
    QString str2 = " entered a ";
    QString str3 = " game called ";
    
    if( text.find( str1 ) >= 0 &&
	text.find( str2 ) >= 0 &&
	text.find( str3 ) >= 0 )
    {
	
	// Yes, this is what we're looking for!
	// Do some arithmetic to find the string.

	// Find the position of where the gameName starts.
	int gameNamePos = text.find( str3 ) + str3.length();

	// Get everything to the right of that position.
	msg.gameName = text.right( text.length() - gameNamePos );

	// Truncate the period at the end.
	msg.gameName.truncate( msg.gameName.length() - 1 );

	msg.type = BnetMessage::FriendJoinedGame;
	return true;
    }
    return false;
}

QString BnetPacketParser::fromUtf8toQString( QDataStream& stream )
{
    Q_INT8 byte;
    QString rv = "";

    while( !stream.atEnd() )
    {
	stream >> byte;
	if( byte != '\0' )
	{
	    rv += (char)byte;
	}
	else
	{
	    break;  // while loop.
	}
    }
    return rv;
}
